package com.xiayuanxing.arithmetic.DataStructures.Sort;

import java.util.Arrays;

/**
 * @program: arithmetic
 * @description: 归并排序
 * @author: xia yuan xing
 * @create: 2021-08-28 14:00
 */
public class MergeSort {


    public static void main(String[] args) {
        int[] array = {8,4,5,7,1,3,6,2};

//        int[] sort = sort(array, 0, array.length - 1);
//        System.out.println(Arrays.toString(sort));
        int[] temp = new int[array.length];
        mergeSort(array,0,array.length-1,temp);
        System.out.println(Arrays.toString(array));
    }


    /**
     * 归并排序：方法一
     * @param a
     * @param low
     * @param high
     * @return
     */
    public static int[] sort(int[] a,int low,int high){
        int mid = (low+high)/2;
        if (low<high){
            sort(a,low,mid);
            sort(a,mid+1,high);
            merge(a,low,mid,high);
        }
        return a;
    }


    public static void merge(int[] a,int low,int mid,int high){
        int[] temp = new int[high-low+1];
        int i =low;
        int j =mid+1;
        int k =0;
        while (i<=mid && j<=high){

            if (a[i] < a[j]){
                temp[k++] = a[i++];
            }else {
                temp[k++] = a[j++];
            }
        }

        while (i<=mid){
            temp[k++] = a[i++];
        }

        while (j<=high){
            temp[k++] = a[j++];
        }

        for (int x =0;x<temp.length;x++){
            a[x+low] = temp[x];
        }
    }


    /**
     * 分+合方法
     * @param array
     * @param left
     * @param right
     * @param temp
     */
    public static void mergeSort(int[] array,int left,int right,int[] temp){

        int mid = (left + right)/2;
        if (left < right){
            //向左递归分解
            mergeSort(array,left,mid,temp);
            //向右递归分解
            mergeSort(array,mid+1,right,temp);
            //合并
            merge1(array,left,mid,right,temp);
        }
    }





    /**
     * 合并的方法
     * @param array 待排序的数组
     * @param left 左边的有序的初始索引
     * @param mid 中间索引（中轴）
     * @param right 右边索引
     * @param temp 中转数组
     */
    public static void merge1(int[] array,int left,int mid,int right,int[] temp){
        //初始化i，左边的有序的初始索引
        int i = left;
        //初始化j，右边的有序的初始索引
        int j = mid + 1;
        //指向中转数组的当前索引
        int t = 0;

        //先把左右两边的数据按照规则填充到temp数组，
        //直到左右两边的有序序列，有一边处理完毕为止

        while (i <= mid && j <= right){
            //如果左边的有序序列的当前元素小于等于右边的当前元素，
            // 就将左边的当前元素填充到temp数组中
            if (array[i] <= array[j]){
                temp[t] = array[i];
                //移动
                t += 1;
                i += 1;
            }else {
                temp[t] = array[j];
                t += 1;
                j += 1;
            }
        }



        //将有剩余数据的一边全部填充到temp中
        //左边剩余
        while (i <= mid){
//            temp[t++] = array[i++];
            temp[t] = array[i];
            //移动
            t += 1;
            i += 1;
        }

        //右边剩余
        while (j <= right){
//            temp[t++] = array[j++];
            temp[t] = array[j];
            t += 1;
            j += 1;
        }


        //将temp数组的元素拷贝到array(不是每次都拷贝)
        t = 0;
        int tempLeft = left;
        while (tempLeft <= right){
            array[tempLeft] = temp[t];
            t += 1;
            tempLeft += 1;
        }


    }




}